using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using Gj.aliyun;
using UnityEngine.Networking;
using Gj.Galaxy.Utils;
using SimpleJSON;
using UnityEngine;
using StreamReader = System.IO.StreamReader;
using StreamWriter = System.IO.StreamWriter;

namespace Gj
{
    public class Manager
    {
        
        public static ManagerSettings settings;
        public static int dataVersion;

        public static string Domain = "";

        static Manager()
        {
            settings = LoadSettings();
        }

        public static void SetDomain(string domain)
        {
            Domain = domain;
        }

        private static ManagerSettings LoadSettings()
        {
            ManagerSettings loadedSettings = (ManagerSettings)Resources.Load("ManagerSettings", typeof(ManagerSettings));
            if (loadedSettings == null)
            {
                loadedSettings = ScriptableObject.CreateInstance<ManagerSettings>();
                // Debug.LogError("ManagerSettings is not exist (Resources)");
            }
            return loadedSettings;
        }

        public static IEnumerator GetRoom(string userId, Action<string> result)
        {
            JSONObject data = new JSONObject();
            data["userId"] = userId;
            data["mapId"] = settings.roomMap;
            return Post($"http://{Domain}{settings.roomUrl}", data, (r) => { result(r.ToString()); });
        }
        
        public static IEnumerator SearchUser(string keyword, int number, int page, Action<JSONArray> result)
        {
            JSONObject data = new JSONObject();
            data["keyword"] = keyword;
            data["number"] = number;
            data["page"] = page;
            // Debug.LogError($"http://{Manager.Domain}{Manager.settings.userUrl}");
            return Manager.Get($"http://{Manager.Domain}{Manager.settings.userUrl}", data, (r) =>
            {
                if (r != null)
                {
                    result(r.AsArray);
                }
                else
                {
                    result(null);
                }
            });
        }

        public static IEnumerator GetVersion(Action<int> callback)
        {
            return Get($"http://{Domain}{settings.dataVersionUrl}", null, (r) =>
            {
                callback(r.AsInt);
            });
        }

        public static string DataZipFile()
        {
#if UNITY_ANDROID && !UNITY_EDITOR
            string uri = Application.streamingAssetsPath + "/";
#else
            string uri = Application.streamingAssetsPath + "/";
#endif
            return uri + settings.dataFile;
        }
        
        public static IEnumerator LoadDataWithZip(Action<string, byte[]> callback)
        {
            var file = DataZipFile();
            yield return LoadWithZip(file, callback);
        }

        public static IEnumerator DownloadData(Action<string, byte[]> callback, Action finish = null)
        {
            int current = 0;
            yield return GetVersion((v) => { current = v; });
            if (current <= dataVersion)
            {
                // Debug.Log("no need update version:"+current+"; last"+dataVersion);
                finish?.Invoke();
                yield break;
            }

            // Debug.Log("need update version:"+dataVersion+": last"+current);
            yield return DownloadData(new string[0], false, (b) =>
            {
                MemoryStream memoryStream = new MemoryStream(b);
                LoadZipStream(memoryStream, entry =>
                {
                    MemoryStream stream = new MemoryStream();
                    int size = 2048;
                    byte[] data = new byte[2048];
                    var s = entry.Open();
                    while (true)       //  循环写入单个文件
                    {
                        size = s.Read(data, 0, data.Length);  
                        if (size > 0) 
                        {
                            stream.Write(data, 0, size);     // 每次写入的文件大小
                        } 
                        else 
                        {
                            break;
                        }
                    }
                    callback(entry.Name, stream.ToArray());
                });
            });
            
            finish?.Invoke();
            dataVersion = current;
            // Debug.Log("finish update version");
            yield break;
        }
        
#if UNITY_EDITOR
        public static IEnumerator DownloadDataFile()
        {
            string directoryName = Path.GetFullPath(settings.dataDir);   // 获取解压后保存到的文件夹
            FileTools.DeleteFolder(directoryName);
            // Debug.Log("delete dataDir");
            //生成解压目录
            Directory.CreateDirectory(directoryName);
            // Debug.Log("create dataDir");
            return DownloadData(new string[0], false,(b ) =>
            {
                MemoryStream memoryStream = new MemoryStream(b);
                LoadZipStream(memoryStream, entry =>
                {
                    SaveZipToLocal(directoryName, entry);
                });
            });
        }
        public static IEnumerator DownloadDataZip()
        {
            var file = "android/unityLibrary/src/main/assets/"+settings.dataFile;
            // Debug.Log("Download:"+file);
            var dir = Path.GetDirectoryName(file);
            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
            File.Delete(file);
            return DownloadData(new string[0], false,(b ) =>
            {
                // Debug.Log("Download size:"+b.Length);
                File.WriteAllBytes(file, b);
            });
        }
        public static IEnumerator DownloadManagerDataFile()
        {
            string directoryName = Path.GetFullPath(settings.managerDataDir);   // 获取解压后保存到的文件夹
            FileTools.DeleteFolder(directoryName);
            // Debug.Log("delete dataDir");
            //生成解压目录
            Directory.CreateDirectory(directoryName);
            // Debug.Log("create dataDir");
            return DownloadData(new string[0], true, (b ) =>
            {
                MemoryStream memoryStream = new MemoryStream(b);
                LoadZipStream(memoryStream, entry =>
                {
                    SaveZipToLocal(directoryName, entry);
                });
            });
        }
#endif

        public static IEnumerator DownloadData(string[] data, bool manager, Action<byte[]> callback)
        {
            var url = $"http://{Domain}{settings.dataUrl}?";
            foreach (var d in data)
            {
                url += "data=" + d + "&";
            }

            if (manager)
            {
                url += "manager=1&";
            }
            return Download(url, (b) =>
            {
                if (b.Length == 0)
                {
                    // Debug.LogErrorFormat("Data {0} size is zero", settings.dataUrl);
                    return;
                }
                // Debug.LogError(b.Length);

                callback(b);
            });
        }

        public static void SaveZipToLocal(string directoryName, ZipArchiveEntry entry)
        {
            var dir = Path.GetDirectoryName(directoryName + "/" + entry.FullName);
            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
            //解压文件到指定的目录
            FileStream streamWriter = File.Create(directoryName+"/"+entry.FullName);
                    
            int size = 2048;
            byte[] data = new byte[2048];
            var s = entry.Open();
            while (true)       //  循环写入单个文件
            {
                size = s.Read(data, 0, data.Length);  
                if (size > 0) 
                {
                    streamWriter.Write(data, 0, size);     // 每次写入的文件大小
                } 
                else 
                {
                    break;
                }
            }
                    
            streamWriter.Close();
        }

        public static void Copy(string oldFile, string newFile)
        {
            //解压文件到指定的目录
            FileStream streamWriter = File.Create(newFile);
                    
            int size = 2048;
            byte[] data = new byte[2048];
            var s = File.OpenRead(oldFile);
            while (true)       //  循环写入单个文件
            {
                size = s.Read(data, 0, data.Length);  
                if (size > 0) 
                {
                    streamWriter.Write(data, 0, size);     // 每次写入的文件大小
                } 
                else 
                {
                    break;
                }
            }
                    
            streamWriter.Close();
        }
        
        public static IEnumerator LoadZip(string file, Action<ZipArchiveEntry> callback)
        {
            
#if UNITY_ANDROID && !UNITY_EDITOR
        MemoryStream memoryStream;
        byte[] zipData;
        if (file.Contains("://")){
            // Android stream 必须用 UnityWebRequest
            UnityWebRequest request = UnityWebRequest.Get(file);
            yield return request.SendWebRequest();

            if (request.isNetworkError || request.isHttpError)
            {
                Debug.LogError($"Failed to load ZIP: {request.error}");
                yield break;
            }

            // 从下载的数据创建 MemoryStream
            zipData = request.downloadHandler.data;
            memoryStream = new MemoryStream(zipData);
        } else {
            zipData = File.ReadAllBytes(file);
            memoryStream = new MemoryStream(zipData);
        }
#else
                // 其他平台（Windows/Mac/iOS）直接读取文件
                byte[] zipData = File.ReadAllBytes(file);
                MemoryStream memoryStream = new MemoryStream(zipData);
#endif
            LoadZipStream(memoryStream, callback);
            memoryStream.Close();
            
            // Debug.Log($"end: {zipData.Length}");
            yield break;
        }

        public static void LoadZipStream(Stream stream, Action<ZipArchiveEntry> callback)
        {
            using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read))
            {
                var e = archive.Entries.GetEnumerator();
                // Debug.Log("open zip");
                while (e.MoveNext())
                {
                    var entry = e.Current;
                    string fileName = Path.GetFileName(entry.Name);
                    if (fileName != String.Empty)
                    {
                        callback(entry);
                    }
                }
                e.Dispose();
            }
        }

        public static void SaveToZip(string file, Dictionary<string, byte[]> data)
        {
            var dir = Path.GetDirectoryName(file);
            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
            // Debug.LogError($"SaveToZip {file}");
            using (FileStream zipFileStream = new FileStream(file, FileMode.Create))
            using (ZipArchive archive = new ZipArchive(zipFileStream, ZipArchiveMode.Create))
            {
                foreach (var entryData in data)
                {
                    string entryName = entryData.Key;
                    byte[] content = entryData.Value;

                    if (string.IsNullOrEmpty(entryName) || content == null)
                    {
                        Debug.LogWarning($"Skipping invalid entry: {entryName}");
                        continue;
                    }

                    ZipArchiveEntry entry = archive.CreateEntry(entryName);
                    using (Stream entryStream = entry.Open())
                    {
                        entryStream.Write(content, 0, content.Length);
                    }
                }
            }
        }

        public static IEnumerator LoadWithZip(string file, Action<Dictionary<string, byte[]>> callback)
        {
            var inside = new Dictionary<string, byte[]>();
            yield return LoadWithZip(file, (s, bytes) =>
            {
                inside[s] = bytes;
            });
            callback(inside);
        }
        
        public static IEnumerator LoadWithZip(string file, Action<string, byte[]> callback)
        {
            // Debug.LogError($"LoadWithZip {file} {File.Exists(file)}");
            yield return LoadZip(file, (entry) =>
            {
                // Debug.LogError($"LoadWithZip {file} -> {entry.FullName}");
                MemoryStream stream = new MemoryStream();
                int size = 2048;
                byte[] data = new byte[2048];
                var s = entry.Open();
                while (true)       //  循环写入单个文件
                {
                    size = s.Read(data, 0, data.Length);  
                    if (size > 0) 
                    {
                        stream.Write(data, 0, size);     // 每次写入的文件大小
                    } 
                    else 
                    {
                        break;
                    }
                }
                callback(entry.Name, stream.ToArray());
            });
        }

        public static IEnumerator DownloadMap(string onlinePath, string localPath, Action<bool, string> cb)
        {
            // Debug.LogError(1);
            if (File.Exists(localPath))
            {
                cb(true, "");
                yield break;
            }
            // Debug.LogError(2);

            Aliyun.DownloadOSS(onlinePath, "", Aliyun.settings.MapDir, (ok, content) =>
            {           
                // Debug.LogError(3);
                if (ok)
                { 
                    // Debug.LogError(4);
                    // Debug.LogError(content.Length);
                    var dir = Path.GetDirectoryName(localPath);
                    if (!Directory.Exists(dir))
                    {
                        Directory.CreateDirectory(dir);
                    }
                    FileStream streamWriter = File.Create(localPath);
                    streamWriter.Write(content, 0, content.Length);
                    streamWriter.Close();
                    cb(true, "");
                }
                else
                {
                    // Debug.LogError(5);
                    cb(false, "");
                }
            });
        }

        public static void Download(string path, string dir, Action<bool, byte[]> cb)
        {
            Aliyun.DownloadOSS(path, "", dir, cb);
        }

        public static void DownloadPNG(string path, string dir, Action<bool, byte[]> cb)
        {
            Aliyun.DownloadOSS(path, ".png", dir, cb);
        }

        public static void UploadMap(string localPath, string onlinePath, Action<bool, string> cb)
        {
            if (!File.Exists(localPath))
            {
                cb(false, "");
                return;
            }

            byte[] filebytes = File.ReadAllBytes(localPath);
            Aliyun.UploadOSS(onlinePath, "", Aliyun.settings.MapDir, filebytes, "application/zip", cb);
        }

        public static void UploadMapThumb(string localPath, string onlinePath, Action<bool, string> cb)
        {
            if (!File.Exists(localPath))
            {
                cb(false, "");
                return;
            }

            byte[] filebytes = File.ReadAllBytes(localPath);
            Aliyun.UploadOSS(onlinePath, ".png", Aliyun.settings.MapThumbDir, filebytes, "application/png", cb);
        }

        public static void UploadMapThumb(byte[] file, string onlinePath, Action<bool, string> cb)
        {
            Aliyun.UploadOSS(onlinePath, ".png", Aliyun.settings.MapThumbDir, file, "application/png", cb);
        }

        public static IEnumerator DBGet(string db, string id, Action<JSONObject> result)
        {
            JSONObject data = new JSONObject();
            return Get($"http://{Domain}/system/db/{db}/{id}", data, (r) => { result(r.AsObject); });
        }
        public static IEnumerator Download(string url, Action<byte[]> result)
        {
            // 可以根据需求添加其他参数，服务端负责解析
            Dictionary<string,string> headers = new Dictionary<string, string> ();
            headers.Add("Content-type", "application/json");
            headers.Add("token", settings.authToken);
            var instance = HttpTools.GetInstance();
            Dictionary<string,string> d = new Dictionary<string, string> ();
            // Debug.Log("download data");
            // Debug.Log(url);
            return instance.Get(url, d, headers, (bool success, WWW www) =>
            {
                if (!success)
                {
                    // Debug.LogErrorFormat("url {0} fail", url);
                    return;
                }
                result(www.bytes);
            });
        }

        public static IEnumerator Get(string url, JSONObject data, Action<JSONNode> result)
        {
            // 可以根据需求添加其他参数，服务端负责解析
            Dictionary<string,string> headers = new Dictionary<string, string> ();
            headers.Add("Content-type", "application/json");
            headers.Add("token", settings.authToken);
            Debug.LogError("token:"+settings.authToken);
            var instance = HttpTools.GetInstance();
            Dictionary<string,string> d = new Dictionary<string, string> ();
            if (data != null)
            {
                var e = data.GetEnumerator();
                while (e.MoveNext())
                {
                    var c = (KeyValuePair<string, JSONNode>)e.Current;
                    d.Add(c.Key, c.Value);
                }
            }
            
            return instance.Get(url, d, headers, (bool success, WWW www) =>
            {
                if (!success)
                {
                    Debug.LogErrorFormat("url {0} fail", url);
                    return;
                }
                Debug.Log("url"+url+":"+www.text);
                if (www.text.Length == 0)
                {
                    Debug.LogErrorFormat("url {0} fail", url);
                    return;
                }
                var info = JSONNode.Parse (www.text);
                if (info ["status"].AsInt != 200)
                {
                    Debug.LogError(info);
                }
                else
                {
                    result(info["result"]);
                }
            });
        }

        public static IEnumerator Post(string url, JSONObject data, Action<JSONNode> result)
        {
            // 可以根据需求添加其他参数，服务端负责解析
            Dictionary<string,string> headers = new Dictionary<string, string> ();
            headers.Add("Content-type", "application/json");
            headers.Add("token", settings.authToken);
            var instance = HttpTools.GetInstance();
                
            return instance.Post(url, data.ToString(), headers, (bool success, WWW www) =>
            {
                if (!success)
                {
                    // Debug.LogErrorFormat("url {0} fail", url);
                    return;
                }
                // Debug.Log(www.text);
                var info = JSONNode.Parse (www.text);
                if (info ["status"].AsInt != 200)
                {
                    // Debug.LogError(info);
                }
                else
                {
                    result(info["result"]);
                }
            });
        }
    }
}